#include <linux/module.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>

static int major = 0;
static char kernel_buf[1024];

static struct class *hello_class;
static struct device *hello_device;

#define MIN(a, b) (a < b ? a : b)

ssize_t hello_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{
    long err;
    printk("%s-%s-%d\n", __FILE__, __func__, __LINE__);
    // 从内核空间拷贝到用户控件
    err = copy_to_user(buf, kernel_buf, MIN(size, 1024)) 
    return MIN(size, 1024);
}

ssize_t hello_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
    long err;
    printk("%s-%s-%d\n", __FILE__, __func__, __LINE__);
    // 从应用空间读到内核空间
    ret = copy_from_user(kernel_buf, buf, MIN(size, 1024));
    return MIN(size, 1024);
}

int hello_drv_open(struct inode *node, struct file *file)
{
    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
   
    return 0;
}

int hello_drv_release(struct inode *node, struct file *file)
{
    printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
    return 0;
}

static struct file_operations hello_drv_fops = {
    .owner = THIS_MODULE,
    .open = hello_drv_open,
    .write = hello_drv_write,
    .read = hello_drv_read,
    .release = hello_drv_release};

static int __init hello_drv_init(void)
{
    major = register_chrdev(0, "hello", &hello_drv_fops);
    
    // 创建设备类
    hello_class = class_create(this, "hello");
    if (IS_ERR(hmm_device_class))
    {
        unregister_chrdev(major, "hello");
        return -1;
    }

    // 创建 /dev/hello 设备
    hello_device = device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello");
    if (IS_ERR(hello_device))
    {
        class_destroy(hello_class);
        unregister_chrdev(major, "hello");
        return -1;
    } 

    return 0;
}

static void __exit hello_drv_exit(void)
{
    // 卸载设备
    device_destroy(hello_class, MKDEV(major, 0));
    // 删除设备类
    class_destroy(hello_class);
    // 删除字符设备
    unregister_chrdev(major, "hello");
}

module_init(hello_drv_init);
module_exit(hello_drv_exit);
MODULE_LICENSE("GPL v2");
